package boundedWildcards;

import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: Georgiana.Scarlat
 * Date: 8/30/12
 * Time: 10:35 AM
 *
 */
public class ParametrizedPriorityQueue<T extends Comparable<? super T>> {

    private T[] objects;
    private static final int INITIAL_CAPACITY = 15;
    int size;

    @SuppressWarnings("unchecked")
    public ParametrizedPriorityQueue() {
        objects = (T[]) new Comparable[INITIAL_CAPACITY];
    }

    public void push(T object){

        extendCapacityIfNecessary();

        int index = getIndexInWhichToInsert(object);

        makeSpaceForInsertion(index);

        objects[index] = object;

        size++;

    }

    public void pushAll(Iterable<? extends T> tobeAdded){
        for(T elem:tobeAdded)
            push(elem);
    }

    public void popAll(Collection<? super T> whereToPop){

        while (hasMoreElements())
            whereToPop.add(pop());
    }

    private void makeSpaceForInsertion(int index) {

        System.arraycopy(objects, index, objects, index + 1, size - index);
    }

    private int getIndexInWhichToInsert(T object) {
        int index;
        for(index = 0;index<size;index++){
            if(object.compareTo(objects[index]) < 0)
                return index;
        }


        return index;
    }

    public boolean hasMoreElements(){
        return size > 0;
    }

    public T pop()  {
        if(!hasMoreElements())
            throw new  UnsupportedOperationException("Can't pop from empty priority queue.");
        T result = objects[--size];
        objects[size] = null;
        return result;
    }

    private void extendCapacityIfNecessary() {

        if(size == objects.length){
            objects = Arrays.copyOf(objects, size * 2);
        }
    }

    @Override
    public String toString() {
        return "PriorityQueue{" +
                "objects=" + (objects == null ? null : Arrays.asList(Arrays.copyOf(objects,size))) +
                '}';
    }

    public static void main(String[] args) {

        ParametrizedPriorityQueue<Integer> priorityQueue = makeAnIntegerPriorityQueue();

        getBiggestElementFromPQ(priorityQueue);

        tryToAddMoreSpecificCollection();

        tryToAddToMoreGeneralCollection();

    }

    private static void tryToAddToMoreGeneralCollection() {

        ParametrizedPriorityQueue<ASubComparable> priorityQueue = new ParametrizedPriorityQueue<ASubComparable>();
        priorityQueue.push(new ASubComparable(1));
        priorityQueue.push(new ASubComparable(2));

        Set<AComparable> whereToPopTo = new HashSet<AComparable>();
        priorityQueue.popAll(whereToPopTo);
        System.out.println(whereToPopTo);
    }

    private static void tryToAddMoreSpecificCollection() {

        ParametrizedPriorityQueue<AComparable> priorityQueue = new ParametrizedPriorityQueue<AComparable>();
        priorityQueue.push(new AComparable(3));

        List<ASubComparable> toBeAdded = new LinkedList<ASubComparable>();
        toBeAdded.add(new ASubComparable(2));
        toBeAdded.add(new ASubComparable(4));

        priorityQueue.pushAll(toBeAdded);

        System.out.println(priorityQueue);
    }


    private static void getBiggestElementFromPQ(ParametrizedPriorityQueue<Integer> priorityQueue)  {
        System.out.println("The biggest element: "+priorityQueue.pop());
    }

    private static ParametrizedPriorityQueue<Integer> makeAnIntegerPriorityQueue() {
        ParametrizedPriorityQueue<Integer> priorityQueue = new ParametrizedPriorityQueue<Integer>();

        priorityQueue.push(1);
        priorityQueue.push(10);
        priorityQueue.push(4);
        priorityQueue.push(0);
        priorityQueue.push(11);

        System.out.println(priorityQueue);
        return priorityQueue;
    }
}
